package com.itcs.app.pay.service.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.itcs.app.pay.PayPlatformAdapter;
import com.itcs.app.pay.constants.CallbackPayStatus;
import com.itcs.app.pay.model.QrcodeCallBackData;
import com.itcs.app.pay.model.QrcodeFilterRes;
import com.itcs.app.pay.model.QrcodePayModel;
import com.itcs.app.pay.model.QrcodePayRes;
import com.itcs.app.pay.model.TradePayCallBackData;
import com.itcs.app.pay.model.TradePayModel;
import com.itcs.app.pay.model.TradePayRes;
import com.itcs.app.pay.service.PayService;
import com.itcs.app.service.TransJournalService;
import com.itcs.app.tran.SendBoxSocket;
import com.itcs.app.util.NetworkUtil;
import com.itcs.app.util.ParamMap;
import com.itcs.app.util.PayChannelCode;
import com.itcs.app.util.PayStatus;
import com.itcs.app.util.PayType;
import com.itcs.box.domain.BoxResponse;
import com.itcs.box.util.BoxResUtils;
import com.itcs.box.util.LogUtils;
import com.itcs.trading.mapper.ExitWhitelistOpHisMapper;
import com.itcs.trading.mapper.TransJournalMapper;
import com.itcs.trading.model.ExitWhitelistOpHis;
import com.itcs.trading.model.TransJournal;

/**
 * 支付服务实现类
 * 
 * @author LiuPeng
 * @date 2018年3月24日
 * 
 */
@Service("payService")
public class PayServiceImpl implements PayService, ApplicationContextAware {

	private Log logger = LogFactory.getLog(getClass());
	/**
	 * @Fields 支付平台(暂为配置文件方式),默认为nowpay（现在支付）
	 */
	@Value("${itc.pay.platform:nowpay}")
	private String payPlatform;
	/**
	 * @Fields 订单名
	 */
	@Value("${mhtOrderName}")
	private String orderName;
	/**
	 * @Fields 订单详情
	 */
	@Value("${mhtOrderDetail}")
	private String orderDetail;

	/**
	 * @Fields 已支付提示页面
	 */
	@Value("${pay.alreadyPay.url:/wap3}")
	private String alreadyPayPage;
	@Autowired
	private TransJournalService transJournalService;
	@Autowired
	private TransJournalMapper transJournalMapper;

	@Autowired
	private SendBoxSocket sendBoxSocket;
	
	@Autowired
	private ExitWhitelistOpHisMapper exitWhitelistOpHisMapper;

	private Map<String, PayPlatformAdapter> payPlatformAdapterMap;

	@Override
	public String qrcode(HttpServletRequest request, String payChannelCode) {
		PayPlatformAdapter payPlatformAdapter = payPlatformAdapterMap.get(payPlatform);
		if (payPlatformAdapter != null) {
			// 金额根据实际来
			QrcodeFilterRes qrcodeFilterRes = payPlatformAdapter.qrcodeFilter(request, payChannelCode);
			if (!qrcodeFilterRes.isEndFilter()) {
				return qrcodeFilterRes.getRedirectUrl();
			}

			ParamMap paramMap = qrcodeFilterRes.getOriginalMap();

			// 交易流水号
			String tranNO = paramMap.getString("transacSeq");
			// 交易金额
			String tollFare = paramMap.getString("tollFare");
			// 交易时间
			String tollTime = paramMap.getString("tollTime");
			// 设备id
			String deviceId = paramMap.getString("deviceId");
			// 车牌
			String carPlate = paramMap.getString("carPlate");

			// 查看订单号对象
			TransJournal traderecords = transJournalService.selectByTransNo(tranNO);
			if (traderecords == null) {
				logger.info(LogUtils.build("xzzfzs", "现在支付主扫", "生成主扫订单：" + tranNO));
				// 支付类型
				int payerId = PayType.主扫微信;
				if (PayChannelCode.支付宝支付.equals(payChannelCode)) {
					payerId = PayType.主扫支付宝;
				}
				// 创建订单
				traderecords = new TransJournal(tranNO, new BigDecimal(tollFare), Long.parseLong(deviceId), payerId, tollTime);
				// 设置车牌
				traderecords.setCarPlate(carPlate);
				traderecords.setRemark(paramMap.getString("openId"));//添加用户ID
				transJournalMapper.insert(traderecords);
			} else {
				if (traderecords.getPayState() == 2 || traderecords.getPayState() == 5) {
					// 已支付
					logger.info(LogUtils.build("xzzfzs", "现在支付主扫", "订单已被支付已支付：" + tranNO));
					Map<String, String> data = new HashMap<>();
					data.put("isok", "1");
					request.setAttribute("data", data);
					return alreadyPayPage;
				} else {
					// 设置车牌
					traderecords.setCarPlate(carPlate);
					// 更新金额
					traderecords.setTollFare(new BigDecimal(tollFare));// 金额单位转化
					transJournalMapper.updateByPrimaryKey(traderecords);
				}
			}
			// 支付金额
			BigDecimal tollFareValue = new BigDecimal(tollFare);
			String tollFareYStr = tollFareValue.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP).toString();
			String mhtOrderDetail = MessageFormat.format(orderDetail, tollFareYStr);
			// 获取请求ip
			String ip = NetworkUtil.getIpAddress(request);

			QrcodePayModel qrcodePayModel = new QrcodePayModel(payChannelCode, tranNO, tollFare, orderName, mhtOrderDetail,
					qrcodeFilterRes.getFilterParams(), ip);
			// 调用
			QrcodePayRes res = payPlatformAdapter.qrcode(qrcodePayModel);
			request.setAttribute("data", res.getData());
			return res.getPageUrl();
		}
		return null;
	}

	@Override
	public TradePayRes tradePay(TradePayModel tradePayModel) {
		PayPlatformAdapter payPlatformAdapter = payPlatformAdapterMap.get(payPlatform);
		if (payPlatformAdapter != null) {
			return payPlatformAdapter.tradePay(tradePayModel);
		}
		return null;
	}

	@Override
	public void qrcodeCallback(QrcodeCallBackData qrcodeCallBackData) {
		String transNo = qrcodeCallBackData.getTransNo();
		String payResult = "9";
		TransJournal etcsTraderecord = transJournalService.selectByTransNo(transNo);
		Long deviceId = etcsTraderecord.getTerminalNo();// 通讯盒ID
		if (etcsTraderecord == null || etcsTraderecord.getPayState() == PayStatus.支付成功 || etcsTraderecord.getPayState() == PayStatus.车道确认支付完成) {
			logger.info(LogUtils.build("qrcodeCallback", "第三方主扫回调", "订单已支付或不存在，回调(2008)通讯盒:" + deviceId, JSON.toJSONString(qrcodeCallBackData)));
			send2008(deviceId, transNo, payResult, qrcodeCallBackData.getPayChannelCode());
			return;
		}

		if (CallbackPayStatus.PAY_SUCCESS.equals(qrcodeCallBackData.getPayStatus())) {
			payResult = "1";
			int payerId = PayType.主扫微信;
			if (PayChannelCode.支付宝支付.equals(qrcodeCallBackData.getPayChannelCode())) {
				payerId = PayType.主扫支付宝;
			}
			etcsTraderecord.setPayerId(payerId);

			String nowPayOrderNo = qrcodeCallBackData.getPlatformOrderNo();
			if (nowPayOrderNo != null) {
				etcsTraderecord.setdOrderNo(nowPayOrderNo);// 现在支付流水号 聚合订单号
			}
			String channelOrderNo = qrcodeCallBackData.getChannelOrderNo();
			if (channelOrderNo != null) {
				etcsTraderecord.setsOrderNo(channelOrderNo);// 渠道订单号,微信或支付宝订单号,支付成功时返回 第三方订单号
			}

			// 更新支付状态
			etcsTraderecord.setPayState(PayStatus.支付成功);
			transJournalMapper.updateByPrimaryKey(etcsTraderecord);
			
			//修改为支付成功，清空白名单==================2018-04-20
			// 11、清空某车牌的白名单
			ExitWhitelistOpHis clear = new ExitWhitelistOpHis();
			clear.setCarPlate(etcsTraderecord.getCarPlate());
			exitWhitelistOpHisMapper.deleteWhitelis(clear);
			logger.info("删除已支付车牌白名单,车牌号为["+etcsTraderecord.getCarPlate()+"]");
			//修改为支付成功，清空白名单==================2018-04-20

			logger.info(LogUtils.build("qrcodeCallback", "主扫回调", "支付成功，回调(2008)通讯盒:" + deviceId + "-" + JSON.toJSONString(qrcodeCallBackData)));

			send2008(deviceId, transNo, payResult, qrcodeCallBackData.getPayChannelCode());

		} else {
			// 更新支付状态
			etcsTraderecord.setPayState(PayStatus.支付失败);
			transJournalMapper.updateByPrimaryKey(etcsTraderecord);
			logger.info(LogUtils.build("qrcodeCallback", "主扫回调", "支付失败，回调(2008)通讯盒:" + deviceId + "-" + JSON.toJSONString(qrcodeCallBackData)));
			send2008(deviceId, transNo, payResult, qrcodeCallBackData.getPayChannelCode());
			return;
		}
	}

	@Override
	public void tradePayCallback(TradePayCallBackData tradePayCallBackData) {
		String transNo = tradePayCallBackData.getTransNo();
		String payResult = "9";
		TransJournal etcsTraderecord = transJournalService.selectByTransNo(transNo);
		Long deviceId = etcsTraderecord.getTerminalNo();// 通讯盒ID
		if (etcsTraderecord == null || etcsTraderecord.getPayState() == PayStatus.支付成功 || etcsTraderecord.getPayState() == PayStatus.车道确认支付完成) {
			logger.info(LogUtils.build("tradePayCallback", "被扫回调", "订单已支付或不存在，回调(2008)通讯盒:" + deviceId, JSON.toJSONString(tradePayCallBackData)));
			send2008(deviceId, transNo, payResult, tradePayCallBackData.getPayChannelCode());
			return;
		}

		if (CallbackPayStatus.PAY_SUCCESS.equals(tradePayCallBackData.getPayStatus())) {
			payResult = "1";
			int payerId = PayType.被扫微信;
			if (PayChannelCode.支付宝支付.equals(tradePayCallBackData.getPayChannelCode())) {
				payerId = PayType.被扫支付宝;
			}
			etcsTraderecord.setPayerId(payerId);

			String nowPayOrderNo = tradePayCallBackData.getPlatformOrderNo();
			if (nowPayOrderNo != null) {
				etcsTraderecord.setdOrderNo(nowPayOrderNo);// 现在支付流水号 聚合订单号
			}
			String channelOrderNo = tradePayCallBackData.getChannelOrderNo();
			if (channelOrderNo != null) {
				etcsTraderecord.setsOrderNo(channelOrderNo);// 渠道订单号,微信或支付宝订单号,支付成功时返回 第三方订单号
			}

			// 更新支付状态
			etcsTraderecord.setPayState(PayStatus.支付成功);
			transJournalMapper.updateByPrimaryKey(etcsTraderecord);

			logger.info(LogUtils.build("achBackNotify", "被扫回调", "支付成功，回调(2008)通讯盒:" + deviceId + "-" + JSON.toJSONString(tradePayCallBackData)));

			send2008(deviceId, transNo, payResult, tradePayCallBackData.getPayChannelCode());

		} else {
			// 更新支付状态
			etcsTraderecord.setPayState(PayStatus.支付失败);
			transJournalMapper.updateByPrimaryKey(etcsTraderecord);
			logger.info(LogUtils.build("achBackNotify", "被扫回调", "支付失败，回调(2008)通讯盒:" + deviceId + "-" + JSON.toJSONString(tradePayCallBackData)));
			send2008(deviceId, transNo, payResult, tradePayCallBackData.getPayChannelCode());
			return;
		}
	}

	/**
	 * 发送2008到通讯盒
	 * 
	 * @param deviceId
	 * @param transacSeq
	 * @param payResult
	 * @param payType
	 * @param payChannelCode
	 */
	private void send2008(long deviceId, String transacSeq, String payResult, String payChannelCode) {
		BoxResponse response2008 = BoxResUtils.build2008(String.valueOf(deviceId), transacSeq, payResult, PayType.BOX_二维码, payChannelCode, null);
		sendBoxSocket.pubsubRes2BoxServer(response2008);
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		initPayPlatformAdapters(applicationContext);
	}

	/**
	 * 初始化 第三方平台支付适配器
	 * 
	 * @param applicationContext
	 */
	private void initPayPlatformAdapters(ApplicationContext applicationContext) {
		if (this.payPlatformAdapterMap == null) {
			payPlatformAdapterMap = new HashMap<>();
			Map<String, PayPlatformAdapter> beanMap = BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, PayPlatformAdapter.class,
					true, true);
			for (Map.Entry<String, PayPlatformAdapter> entry : beanMap.entrySet()) {
				payPlatformAdapterMap.put(entry.getValue().getPayPlatformType(), entry.getValue());
			}
			logger.info("初始化 第三方平台支付适配器完成:" + payPlatformAdapterMap.keySet());
		}
	}

}
